package com.jfirer.mvc.core.route.impl;

import com.jfirer.mvc.core.action.Action;
import com.jfirer.mvc.core.route.Router;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

public class RouterImpl implements Router
{
    class HeaderRule
    {
        final String name;
        final String value;

        public HeaderRule(String name, String value)
        {
            this.name = name;
            this.value = value;
        }
    }

    class PathEntry
    {
        final int    index;
        final String name;

        public PathEntry(String name, int index)
        {
            this.index = index;
            this.name = name;
        }
    }

    private final String       method;
    private final HeaderRule[] headerRules;
    private final String       url;
    private final String       name;
    private final String       description;
    private final PathEntry[]  entries;
    private       Action       action;

    public RouterImpl(String[] paths, String name, String url, String method, String[] headerRules)
    {
        this.name = name;
        this.url = url;
        this.method = method;
        HeaderRule[] rules = new HeaderRule[headerRules.length];
        for (int i = 0; i < rules.length; i++)
        {
            if (headerRules[i].indexOf('=') == -1)
            {
                rules[i] = new HeaderRule(headerRules[i], null);
            }
            else
            {
                String[] tmp = headerRules[i].split("=");
                rules[i] = new HeaderRule(tmp[0], tmp[1]);
            }
        }
        this.headerRules = rules;
        description = buildDescription();
        List<PathEntry> list = new ArrayList<PathEntry>();
        for (int i = 0; i < paths.length; i++)
        {
            String each = paths[i];
            if (each.startsWith("{") && each.endsWith("}"))
            {
                String    pathValue = each.substring(1, each.length() - 1);
                PathEntry entry     = new PathEntry(pathValue, i);
                list.add(entry);
            }
        }
        entries = list.toArray(new PathEntry[list.size()]);
    }

    private String buildDescription()
    {
        StringBuilder cache = new StringBuilder();
        cache.append("name:").append(name).append(",description:");
        cache.append(url).append("(method=").append(method).append(",headrules=");
        for (HeaderRule each : headerRules)
        {
            cache.append(each.name).append('=');
            if (each.value != null)
            {
                cache.append(each.value);
            }
            cache.append('&');
        }
        cache.append(')');
        return cache.toString();
    }

    public boolean equals(Object target)
    {
        if (target instanceof RouterImpl == false)
        {
            return false;
        }
        String targetMethod = ((RouterImpl) target).method;
        if (targetMethod.equals(method) == false)
        {
            return false;
        }
        HeaderRule[] targetHeadRules = ((RouterImpl) target).headerRules;
        if (headerRules.length != targetHeadRules.length)
        {
            return false;
        }
        for (HeaderRule targetHeadRule : targetHeadRules)
        {
            for (HeaderRule each : headerRules)
            {
                if (each.name.equals(targetHeadRule.name))
                {
                    if ((each.value == null && targetHeadRule.value == null) || each.value.equals(targetHeadRule.value))
                    {
                        continue;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    public String toString()
    {
        return description;
    }

    @Override
    public boolean match(HttpServletRequest request)
    {
        String method = request.getMethod();
        if (method.equals(this.method) == false)
        {
            return false;
        }
        for (HeaderRule each : headerRules)
        {
            String value = request.getHeader(each.name);
            if (value == null || value.equals(each.value) == false)
            {
                return false;
            }
        }
        return true;
    }

    @Override
    public void bindAction(Action action)
    {
        this.action = action;
    }

    @Override
    public Action bindedAction()
    {
        return action;
    }
}
